/**
 * @param Core.Storage.DaoProxy storage
 * @param Object owner
 */
Core.Storage.PathResolver = function(storage, owner) {
	this.storage = storage;
	this.owner = owner;
};

Core.Storage.PathResolver.prototype = {
		
	/**
	 * Returns plain global or local path to access data.
	 * @param String raw
	 * @param Core.Storage.Trace trace - tracing object or null.
	 */
	evaluate: function(raw, trace) {
		var path = this._processLocalStorage(raw, trace);

		Array.each(this._closures(path), this, function(expr) {
			var inner = expr.slice(1, expr.length - 1).trim(),
				value = this.storage.get(inner, trace, true);
			
			if(!/\}$/.test(value)) { value += "."; }
			
			path = path.replace(new RegExp("^" + expr), value);
			path = path.replace("." + expr, "." + value);
			path = path.replace(expr, "." + value);
		});

		if(this._isComplex(path)) { path = this.evaluate(path, trace); }
		return path.replace(/\.+$/, "");
	},
	
	/**
	 * Process path to replace local storage prefix with valid global path.
	 * @param String raw
	 * @param Core.Storage.Trace trace - tracing object or null.
	 */
	_processLocalStorage: function(raw, trace) {
		if(!raw.contains("/")) { return raw; }
			
		var head = raw.split("/")[0],
			plain = this.evaluate(head, trace);
		
		if(this._isEmpty(plain)) { var uid = Env.stamp(this.owner); }
		else { var uid = Env.stamp(this.storage.get(plain, trace, true)); }
		
		return this._processLocalStorage(raw.replace(head + "/", "..local." + uid + "."), trace);
	},
	
	/**
	 * Returns closures existing in the given path.
	 * @param String raw
	 */
	_closures: function(raw) {
		return raw.match(/\{\s*[\w\.]+\s*\}/g);
	},
	
	/**
	 * Returns whether the given path contains any complex expressions.
	 * @param String raw
	 */
	_isComplex: function(raw) {
		return raw.contains("/") || raw.contains("{");
	},
	
	/**
	 * Returns whether the given path is empty.
	 * @param String raw
	 */
	_isEmpty: function(raw) {
		return /^\.+$/.test(raw) || raw.empty();
	}
};